home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / gawk / gawk213s.zoo / gawk-src-2.13 / field.c < prev    next >
C/C++ Source or Header  |  1991-07-21  |  15KB  |  615 lines

  1. /*
  2.  * field.c - routines for dealing with fields and record parsing
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28.  
  29. static int (*parse_field) P((int, char **, int, char *,
  30.                  Regexp *, void (*)(), NODE *));
  31. static void rebuild_record P((void));
  32. static int re_parse_field P((int, char **, int, char *,
  33.                  Regexp *, void (*)(), NODE *));
  34. static int def_parse_field P((int, char **, int, char *,
  35.                   Regexp *, void (*)(), NODE *));
  36. static int sc_parse_field P((int, char **, int, char *,
  37.                  Regexp *, void (*)(), NODE *));
  38. static int fw_parse_field P((int, char **, int, char *,
  39.                  Regexp *, void (*)(), NODE *));
  40. static void set_element P((int, char *, int, NODE *));
  41.  
  42. static Regexp *FS_regexp = NULL;
  43. static char *parse_extent;    /* marks where to restart parse of record */
  44. static int parse_high_water=0;    /* field number that we have parsed so far */
  45. static int nf_high_water = 0;    /* size of fields_arr */
  46. static char f_empty[] = "\0";
  47. static int resave_fs;
  48. static NODE *save_FS;
  49. static char *save_fs;        /* save current value of FS when line is read,
  50.                  * to be used in deferred parsing
  51.                  */
  52.  
  53. NODE **fields_arr;        /* array of pointers to the field nodes */
  54. int field0_valid = 1;        /* $(>0) has not been changed yet */
  55. NODE *field0;
  56. static NODE **nodes;        /* permanent repository of field nodes */
  57. static int *FIELDWIDTHS = NULL;
  58.  
  59. void
  60. init_fields()
  61. {
  62.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  63.     emalloc(nodes, NODE **, sizeof(NODE *), "init_fields");
  64.     emalloc(field0, NODE *, sizeof(NODE), "init_fields");
  65.     field0->type = Node_val;
  66.     field0->stref = 0;
  67.     field0->stptr = "";
  68.     field0->flags = (STRING|STR|PERM);    /* never free buf */
  69.     fields_arr[0] = field0;
  70.     save_FS = dupnode(FS_node->var_value);
  71.     save_fs = save_FS->stptr;
  72. }
  73.  
  74. static void
  75. grow_fields_arr(num)
  76. int num;
  77. {
  78.     register int t;
  79.     register NODE *n;
  80.  
  81.     erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  82.     erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field");
  83.     for (t = nf_high_water+1; t <= num; t++) {
  84.         getnode(n);
  85.         n->type = Node_val;
  86.         nodes[t] = n;
  87.         fields_arr[t] = nodes[t];
  88.     }
  89.     nf_high_water = num;
  90. }
  91.  
  92. /*ARGSUSED*/
  93. static void
  94. set_field(num, str, len, dummy)
  95. int num;
  96. char *str;
  97. int len;
  98. NODE *dummy;    /* not used -- just to make interface same as set_element */
  99. {
  100.     register NODE *n;
  101.     register int t;
  102.  
  103.     if (num > nf_high_water)
  104.         grow_fields_arr(num);
  105.     n = nodes[num];
  106.     n->stptr = str;
  107.     n->stlen = len;
  108.     n->flags = (PERM|STR|STRING|MAYBE_NUM);
  109.     fields_arr[num] = n;
  110. }
  111.  
  112. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  113. static void
  114. rebuild_record()
  115. {
  116.     register int tlen;
  117.     register NODE *tmp;
  118.     NODE *ofs;
  119.     char *ops;
  120.     register char *cops;
  121.     register NODE **ptr;
  122.     register int ofslen;
  123.  
  124.     tlen = 0;
  125.     ofs = force_string(OFS_node->var_value);
  126.     ofslen = ofs->stlen;
  127.     ptr = &fields_arr[NF];
  128.     while (ptr > &fields_arr[0]) {
  129.         tmp = force_string(*ptr);
  130.         tlen += tmp->stlen;
  131.         ptr--;
  132.     }
  133.     tlen += (NF - 1) * ofslen;
  134.     emalloc(ops, char *, tlen + 2, "fix_fields");
  135.     cops = ops;
  136.     ops[0] = '\0';
  137.     for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) {
  138.         tmp = *ptr;
  139.         if (tmp->stlen == 1)
  140.             *cops++ = tmp->stptr[0];
  141.         else if (tmp->stlen != 0) {
  142.             memcpy(cops, tmp->stptr, tmp->stlen);
  143.             cops += tmp->stlen;
  144.         }
  145.         if (ptr != &fields_arr[NF]) {
  146.             if (ofslen == 1)
  147.                 *cops++ = ofs->stptr[0];
  148.             else if (ofslen != 0) {
  149.                 memcpy(cops, ofs->stptr, ofslen);
  150.                 cops += ofslen;
  151.             }
  152.         }
  153.     }
  154.     tmp = make_str_node(ops, tlen, ALREADY_MALLOCED);
  155.     unref(fields_arr[0]);
  156.     fields_arr[0] = tmp;
  157.     field0_valid = 1;
  158. }
  159.  
  160. /*
  161.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  162.  * or to NF.  At that point, parse only as much as necessary.
  163.  */
  164. void
  165. set_record(buf, cnt, freeold)
  166. char *buf;
  167. int cnt;
  168. int freeold;
  169. {
  170.     register int i;
  171.  
  172.     NF = -1;
  173.     for (i = 1; i <= parse_high_water; i++) {
  174.         unref(fields_arr[i]);
  175.     }
  176.     parse_high_water = 0;
  177.     if (freeold) {
  178.         unref(fields_arr[0]);
  179.         if (resave_fs) {
  180.             resave_fs = 0;
  181.             unref(save_FS);
  182.             save_FS = dupnode(FS_node->var_value);
  183.             save_fs = save_FS->stptr;
  184.         }
  185.         field0->stptr = buf;
  186.         field0->stlen = cnt;
  187.         field0->stref = 1;
  188.         field0->flags = (STRING|STR|PERM|MAYBE_NUM);
  189.         fields_arr[0] = field0;
  190.     }
  191.     fields_arr[0]->flags |= MAYBE_NUM;
  192.     field0_valid = 1;
  193. }
  194.  
  195. void
  196. reset_record()
  197. {
  198.     (void) force_string(fields_arr[0]);
  199.     set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0);
  200. }
  201.  
  202. void
  203. set_NF()
  204. {
  205.     NF = (int) force_number(NF_node->var_value);
  206.     field0_valid = 0;
  207. }
  208.  
  209. /*
  210.  * this is called both from get_field() and from do_split()
  211.  * via (*parse_field)().  This variation is for when FS is a regular
  212.  * expression -- either user-defined or because RS=="" and FS==" "
  213.  */
  214. static int
  215. re_parse_field(up_to, buf, len, fs, rp, set, n)
  216. int up_to;    /* parse only up to this field number */
  217. char **buf;    /* on input: string to parse; on output: point to start next */
  218. int len;
  219. register char *fs;
  220. Regexp *rp;
  221. void (*set) ();    /* routine to set the value of the parsed field */
  222. NODE *n;
  223. {
  224.     register char *scan = *buf;
  225.     register int nf = parse_high_water;
  226.     register char *field;
  227.     register char *end = scan + len;
  228.     char *cp;
  229.  
  230.     if (up_to == HUGE)
  231.         nf = 0;
  232.     if (len == 0)
  233.         return nf;
  234.  
  235.     cp = FS_node->var_value->stptr;
  236.     if (*RS == 0 && *cp == ' ' && *(cp+1) == '\0') {
  237.         while (scan < end
  238.                && (*scan == '\n' || *scan == ' ' || *scan == '\t'))
  239.             scan++;
  240.     }
  241.     field = scan;
  242.     while (scan < end
  243.            && research(rp, scan, (int)(end - scan), 1) != -1
  244.            && nf < up_to) {
  245.         if (REEND(rp, scan) == RESTART(rp, scan)) {    /* null match */
  246.             scan++;
  247.             if (scan == end) {
  248.                 (*set)(++nf, field, scan - field, n);
  249.                 up_to = nf;
  250.                 break;
  251.             }
  252.             continue;
  253.         }
  254.         (*set)(++nf, field, RESTART(rp, scan), n);
  255.         scan += REEND(rp, scan);
  256.         field = scan;
  257.     }
  258.     if (nf != up_to && *RS != 0 && scan < end) {
  259.         (*set)(++nf, scan, (int)(end - scan), n);
  260.         scan = end;
  261.     }
  262.     *buf = scan;
  263.     return (nf);
  264. }
  265.  
  266. /*
  267.  * this is called both from get_field() and from do_split()
  268.  * via (*parse_field)().  This variation is for when FS is a single space
  269.  * character.
  270.  */
  271. static int
  272. def_parse_field(up_to, buf, len, fs, rp, set, n)
  273. int up_to;    /* parse only up to this field number */
  274. char **buf;    /* on input: string to parse; on output: point to start next */
  275. int len;
  276. register char *fs;
  277. Regexp *rp;
  278. void (*set) ();    /* routine to set the value of the parsed field */
  279. NODE *n;
  280. {
  281.     register char *scan = *buf;
  282.     register int nf = parse_high_water;
  283.     register char *field;
  284.     register char *end = scan + len;
  285.  
  286.     if (up_to == HUGE)
  287.         nf = 0;
  288.     if (len == 0)
  289.         return nf;
  290.  
  291.     *end = ' ';    /* sentinel character */
  292.     for (; nf < up_to; scan++) {
  293.         /*
  294.          * special case:  fs is single space, strip leading whitespace 
  295.          */
  296.         while (scan < end && (*scan == ' ' || *scan == '\t'))
  297.             scan++;
  298.         if (scan >= end)
  299.             break;
  300.         field = scan;
  301.         while (*scan != ' ' && *scan != '\t')
  302.             scan++;
  303.         (*set)(++nf, field, (int)(scan - field), n);
  304.         if (scan == end)
  305.             break;
  306.     }
  307.     *buf = scan;
  308.     return nf;
  309. }
  310.  
  311. /*
  312.  * this is called both from get_field() and from do_split()
  313.  * via (*pase_field)().  This variation is for when FS is a single character
  314.  * other than space.
  315.  */
  316. static int
  317. sc_parse_field(up_to, buf, len, fs, rp, set, n)
  318. int up_to;    /* parse only up to this field number */
  319. char **buf;    /* on input: string to parse; on output: point to start next */
  320. int len;
  321. register char *fs;
  322. Regexp *rp;
  323. void (*set) ();    /* ro